<?php

// Načteme texylu
require_once dirname(__FILE__) . '/texyla.php';
if(!function_exists('json_encode')) {
	require_once dirname(__FILE__) . '/json_encode.php';
}
class texylaAjaxFileUpload {
	
	/**
	* texylaAjaxFileUpload je třída starající se o upload obrázků
	* 
	* Použití
	* *******
	* Tuto třídu lze použít dvěma způsoby:
	* **********************************************************************
	* Způsob první:
	* *************
	* Ověříte si práva uživatele na nahrávání souborů (tohle Texyla neřeší) a nastavíte
	* vše potřebné (povolené mime tyty, extenze a adresář do kterého se má nahrávat) a necháte třídu
	* aby vše udělala:
	* 1) Nejprve si ověřte, že uživatel má práva na nahrávání souborů!!!
	* 2) Inicializace třídy:
	* 	$upl = new texylaAjaxFileUpload;
	* 3) Nastavení proměnných:
	* 	povolené extenze a k nim povolené mimetypy nahrávaných souborů:
	* 		$upl->setAllowExtension(array);
	* 	adresář, do kterého se bude nahrávat:
	* 		$upl->setUploadDirName(string);
	* 4) Použití třídy:
	* 	echo $upl->upload();
	* **********************************************************************
	* Způsob druhý:
	* *************
	* Spočívá v inicializaci třídy a následně předání názvu funkce, která se o nahrání souboru postará.
	* Není třeba posílat žádné další nastavení, protože se nepoužije ani nepošle dál
	* Funkce přijme jako parametr název proměnné $_FILESS a návratovou hodnotou je array o 
	* dvou prvcích: array('filename' => empty|string [''|'file.zip'], 'error' => string|empty ['chybová zpráva'|'']);
	* 	$upl = new texylaAjaxFileUpload;
	* 	echo $upl->upload('myUploadHandler');
	* **********************************************************************
	* Způsob třetí: 
	* *************
	* celý upload si vyřešíte sami a jinak, pokud budete chtít použít Ajaxupload v Texyle,
	* musíte pamatovat na návratovou hodnotu, kterou je array o dvou položkách:
	* 	'filename' => sting buď název souboru, nebo prázdné
	* 	'error' => string buď text chybové hlášky nebo prázdné
	* Pamatujte prosím, že vždy musí být jedna z těchto položek prázdná!!!
	* Tuto array encodujete pomocí funkce json_encode() a výsledek zobrazíte (odešlete prohlížeči)	
	*/
	
	/**
	* zde se ukládají povolené extense a k nim přiřazené Mime typy
	* @var array 
	*/
	private $allowed = array();
	
	/**
	* nastavení cesty k uploadu
	* @var string
	*/
	private $dirToUpload = '';
	
	/**
	* název nahrávaného souboru
	* @var string
	*/
	private $fileName = '';
	
	private $extension = '';
	
	private $mimeType = '';
	
	public function __construct() {

	}

	/**
	* zpracování nahraného souboru
	* @param array pole $_FILES['jeho_název']
	* @param string název externí uživatelské funkce zpracovávající nahraný soubor
	* @return array json_encode("filename" => string [empty|filename], "error" => string [empty|error message])
	*/
	public function upload($handler = '') {
		// načte se poslaný název uploadovacího inputu 
		$fileElementName = !empty($_GET['fileToUpload']) ? $_GET['fileToUpload'] : '';

		// odeslání hlavičky pro zakázání kešování výstupu (v případě potřeby doplnit o další)
		header("Cache-Control: no-cache");

		// pokud je handler prázdný postará se o upload tato třída
		if(empty($handler)) {	
			// zjistí se chyby
			$error = $this->getFileUploadError($fileElementName);
			
			//sestaví se vrácená array
			if (!empty($error)) {
				$return = array(
					'filename' => '',
					'error' => $error
				);
			} else {
				$return = array(
					'filename' => $this->fileName,
					'error' => ''
				);
			}
	
		} else {
			/**
			* volání uživatelské funkce,
			* @param string název uživatelské funkce
			* @param array pole $_FILES['jeho_nazev']
			* @return array ("filename" => string [empty|filename], "error" => string [error message|empty]
			*/
			$return = $handler($_FILES[$fileElementName]);		
		}
		return json_encode($return);		
	}
	
	/**
	* Nastavení povolených extenzí souborů a jim odpovídajících povolených Mimetypů
	* @param array povolené extenze a její mimetypy: $a = array('jpg' => array('image/jpeg', 'image/pjpeg'), 'gif' => array('image/gif'),);
	*/
	public function setAllowExtension($allowed) {
		$this->allowed = $allowed;
		if(is_array($this->allowed)) {
			return;
		} 
		trigger_error('Vstupní parametr metody musí být array.', E_USER_ERROR);
	}

	/**
	* Nastavení adresáře pro uložení nahraných souborů
	* @param string název adresáře včetně cesty k němu v rámci filesystému
	*/
	public function setUploadDirName($name) {
		$this->dirToUpload = $name;
	}
	
	/**
	* Metoda slouží k ověření povolených extensí souborů a k nim povolených Mimetypů
	* @param string název poslané $_FILES proměnné
	* @return bool 
	*/
	private function controlExtensionsAndMimeTypes($files) {
		// získání extense
		$a = explode('.', $_FILES[$files]['name']);
		$this->extension = strtolower($a[count($a) - 1]);

		// ověření její platnosti
		if (array_key_exists($this->extension, $this->allowed)) {
			//koncovka souboru je povolená
			
			// zjištění MimeTypu souboru
			if (class_exists('finfo')) {
				$finfo = new finfo();
				$this->mimeType =  $finfo->file($_FILES[$files]['tmp_name']);
			} else if (function_exists('mime_content_type')) {
				$this->mimeType =  mime_content_type($_FILES[$files]['tmp_name']);
			} else {
				return 'Nelze zjistit Mime Typy souborů, funkce <b>mime_content_type</b> ani třída <b>finfo</b> nejsou v systému.';
			}
			
			// jdeme ověřit jestli je povolen i mimetyp
			if (in_array($this->mimeType, $this->allowed[$this->extension])) {
				// vytvoříme bezpečné jméno souboru
				$this->fileName = $this->getWebalizeName($a);
				return true;
			}
		}
		return false;		
	}

	/**
	* získání bezpečného názvu souboru
	* @param array
	* @return string
	*/
	private function getWebalizeName($array) {
		$ex = array_pop($array);
		$na = join('.', $array);
		return Texy::webalize($na) . "." . $ex;
	}
	
	/**
	* zjistit popis chyby ve $_FILES a další chyby při nahrávání souboru
	* @param string název proměnné $_FILES, (je posílán v $_GET['fileToUpload'])
	* @return false|string
	*/
	private function getFileUploadError($fileElementName) {
		if (empty($fileElementName)) {
			return 'Nebyl poslán název proměnné, ve které mám hledat uploadovaný soubor.';
		}
		
		// kontrola hlášek z $_FILES[][error]
		if (!empty($_FILES[$fileElementName]['error']))  {
			switch($_FILES[$fileElementName]['error']) {
				case '1':
				return 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
				break;
				case '2':
				return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
				break;
				case '3':
				return 'The uploaded file was only partially uploaded';
				break;
				case '4':
				return 'No file was uploaded.';
				break;
				case '6':
				return 'Missing a temporary folder';
				break;
				case '7':
				return 'Failed to write file to disk';
				break;
				case '8':
				return 'File upload stopped by extension';
				break;
				default:
				return 'No error code avaiable';
			}
		}
		
		// ověření jména adresře, do kterého se mají přesouvat nahrané soubory
		if (empty($this->dirToUpload)) {
			return 'Není nastaven adresář do kterého se mají přesouvat nahrané soubory.';
		}
		
		// ověření existence proměnné $_FILES
		if (empty($_FILES[$fileElementName])) {
			return 'Var: $_FILES["' . $fileElementName . '"] is not exists.';
		}

		//ověření Extenze a k ní povolených mimetypů
		$errMime = $this->controlExtensionsAndMimeTypes($fileElementName);
		if ($errMime === false) {
			return "Extension: " . $this->extension . " and/or Mime type: " . $this->mimeType . " uploaded files is not allowed.";			
		}
		if (is_string($errMime)) {
			return $errMime;
		}

		// složíme jméno souboru a cestu 
		$file = $this->dirToUpload . '/' . $this->fileName;
		
		// soubor se stejným názvem již v adresáři existuje
		if (file_exists($file)) {
			return "File already exists!";
		}
		
		// Nahraný soubor v dočasném adresáři neexistuje
		if (empty($_FILES[$fileElementName]['tmp_name']) || $_FILES[$fileElementName]['tmp_name'] == 'none') {
			return 'No file was uploaded (tmp_name is empty).';
		}

			
		// pokusíme se přesunout soubor z tempu do požadovaného adresáře
		if (!@move_uploaded_file($_FILES[$fileElementName]['tmp_name'], $file)) {
			return "Nedostatečná práva pro zápis do: " . $this->dirToUpload . ".";
		}
		
		// soubor je nahrán,  nastavíme práva souboru
		if (!@chmod($file, 0777)) {
			return "Nepodařilo se nastavit přístupová práva pro nahraný soubor.";
		}
		
		// OK, žádná chyba, vrátíme false 
		return false;
	}
}
?>
